#include "sharelist.h"
#include "ui_sharelist.h"

#include <common/downloadtask.h>
#include <common/logininfoinstance.h>

#include <QFileDialog>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>
#include <QMessageBox>
#include <QNetworkReply>

#include <widget/filepropertyinfo.h>

sharelist::sharelist(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::sharelist)
{
    ui->setupUi(this);

    initListWidget();

    addActionMenu();
    m_manager = Common::getNetManager();

    connect(&m_downloadTimer, &QTimer::timeout, [=]()
    {
        downloadFilesAction();
    });

    m_downloadTimer.start(500);
}

sharelist::~sharelist()
{
    delete ui;
}

void sharelist::rightMenu(const QPoint &pos)
{
    QListWidgetItem* item = ui->listWidget->itemAt(pos);

    if(item == NULL)
    {
        m_menuEmpty->exec(QCursor::pos());
    }
    else
    {
        ui->listWidget->setCurrentItem(item);
        m_menu->exec(QCursor::pos());
    }
}

void sharelist::initListWidget()
{
    ui->listWidget->setViewMode(QListView::IconMode);;
    ui->listWidget->setIconSize(QSize(40, 40));
    ui->listWidget->setGridSize(QSize(60, 100));

    ui->listWidget->setResizeMode(QListView::Adjust);

    ui->listWidget->setMovement(QListView::Static);
    //设置图标之间的间距，当setGridSize（）时，此选项无效
    ui->listWidget->setSpacing(30);

    ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &sharelist::rightMenu);
}

void sharelist::addActionMenu()
{
    m_menu = new QMenu(this);
    m_downlodAction = new QAction("下载", this);
    m_propertyAction = new QAction("属性", this);
    m_cancelAction = new QAction("取消分享", this);
    m_saveAction = new QAction("转存文件", this);

    m_menu->addAction(m_downlodAction);
    m_menu->addAction(m_propertyAction);
    m_menu->addAction(m_cancelAction);
    m_menu->addAction(m_saveAction);

    m_menuEmpty = new QMenu(this);
    m_refreshAction = new QAction("刷新", this);
    m_pvAscendingAction = new QAction("按下载量升序", this);
    m_pvDescendingAction = new QAction("按下载量降序", this);
    m_menuEmpty->addAction(m_refreshAction);
    m_menuEmpty->addAction(m_pvAscendingAction);
    m_menuEmpty->addAction(m_pvDescendingAction);

    connect(m_downlodAction, &QAction::triggered, [=]()
    {
        cout << "下载动作";
        addDownloadFiles();
    });

    connect(m_cancelAction, &QAction::triggered, [=]()
    {
        cout << "取消分享动作";
        dealSelectdFile("cancel");
    });

    connect(m_saveAction, &QAction::triggered, [=]()
    {
        cout << "转存文件";
        dealSelectdFile("save");
    });

    connect(m_propertyAction, &QAction::triggered, [=]()
    {
        cout << "属性动作";
        dealSelectdFile("property");
    });

    connect(m_refreshAction, &QAction::triggered, [=]()
    {
        cout << "刷新动作";
        refreshFiles();
    });

    connect(m_pvAscendingAction, &QAction::triggered, [=]()
    {
        cout << "按下载量升序";
        refreshFiles(Display::PvAsc);
    });

    connect(m_pvDescendingAction, &QAction::triggered, [=]()
    {
        cout << "按下载量降序";
        refreshFiles(Display::PvDesc);
    });
}

void sharelist::downloadFilesAction()
{
    DownloadTask* p = DownloadTask::getInstance();
    if(p == nullptr)
    {
        cout << "DownloadTask::getInstance() == NULL";
        return;
    }

    if(p->isEmpty())
    {
        return;
    }

    if(p->isDownload())
    {
        return;
    }

    if(p->isShareTask() == false)
    {
        return;
    }

    DownloadInfo* info = p->takeTask();
    QUrl url = info->url;
    QFile* file = info->file;
    QString md5 = info->md5;
    QString filename = info->filename;
    DataProgress* dp = info->dp;

    QNetworkReply* reply = m_manager->get(QNetworkRequest(url));
    if(reply == nullptr)
    {
        p->dealDownloadTask();
        cout << "get error";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        cout << "下载完成时";
        reply->deleteLater();
        p->dealDownloadTask();

        LoginInfoInstance* login = LoginInfoInstance::getInstance();
        m_cm.writeRecord(login->getUser(), filename, "010");
        dealFilePv(md5, filename);
    });

    connect(reply, &QNetworkReply::readyRead, [=]()
    {
        if(file != nullptr)
        {
            file->write(reply->readAll());
        }
    });

    // 有可用数据更新时
    connect(reply, &QNetworkReply::downloadProgress, [=](qint64 bytesRead, qint64 totalBytes)
    {
        dp->setProgress(bytesRead, totalBytes);// 设置进度
    });
}

void sharelist::refreshFiles(Display cmd)
{
    m_userFilesCount = 0;
    LoginInfoInstance* login = LoginInfoInstance::getInstance();

    QString url = QString("http://%1:%2/sharefiles?cmd=count").arg(login->getIp()).arg(login->getPort());

    QNetworkReply* reply = m_manager->get(QNetworkRequest(QUrl(url)));
    if(reply == nullptr)
    {
        cout << "reply == nullptr";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        if(reply->error() != QNetworkReply::NoError)
        {
            cout << reply->errorString();
            reply->deleteLater();
            return;
        }

        QByteArray array = reply->readAll();
        reply->deleteLater();

        clearshareFileList();

        m_userFilesCount = array.toLong();
        cout << "m_userFilesCount = " << m_userFilesCount;
        if(m_userFilesCount > 0)
        {
            m_start = 0;
            m_count = 10;

            getUserFilesList(cmd);
        }
        else
        {
            refreshFileItems();
        }
    });
}

void sharelist::clearshareFileList()
{
    int n = m_shareFileList.size();
    for(int i = 0; i < n; i++)
    {
        FileInfo* tmp = m_shareFileList.takeFirst();
        delete tmp;
    }
}

void sharelist::clearItems()
{
    int n = ui->listWidget->count();
    for(int i = 0; i < n; ++i)
    {
        QListWidgetItem* item = ui->listWidget->takeItem(0);
        delete item;
    }
}

void sharelist::getUserFilesList(Display cmd)
{
    if(m_userFilesCount <= 0)
    {
        cout << "获取共享文件列表条件结束";
        refreshFileItems();
        return;
    }
    else if(m_count > m_userFilesCount)
    {
        m_count = m_userFilesCount;
    }

    QNetworkRequest request;

    LoginInfoInstance* login = LoginInfoInstance::getInstance();
    QString url;
    QString tmp;
    if(cmd == Normal)
    {
        tmp = "normal";
    }
    else if(cmd == PvAsc)
    {
        tmp = "pvasc";
    }
    else if(cmd == PvDesc)
    {
        tmp = "pvdesc";
    }

    url = QString("http://%1:%2/sharefiles?cmd=%3").arg(login->getIp()).arg(login->getPort()).arg(tmp);
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    /*
        {
            "start": 0,
            "count": 10
        }
    */
    QByteArray data = setFilesListJson(m_start, m_count);

    m_start += m_count;
    m_userFilesCount -= m_count;

    QNetworkReply* reply = m_manager->post(request, data);
    if(reply == nullptr)
    {
        cout << "reply == nullptr";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        if(reply->error() != QNetworkReply::NoError)
        {
            cout << reply->errorString();
            reply->deleteLater();
            return;
        }

        QByteArray array = reply->readAll();
        reply->deleteLater();

        if("015" != m_cm.getCode(array))
        {
            getFileJsonInfo(array);
            getUserFilesList();
        }
    });
}

void sharelist::refreshFileItems()
{
    clearItems();

    int n = m_shareFileList.size();
    for(int i = 0; i < n; ++i)
    {
        FileInfo* tmp = m_shareFileList.at(i);
        QListWidgetItem* item = tmp->item;
        ui->listWidget->addItem(item);
    }
}

QByteArray sharelist::setFilesListJson(int start, int count)
{
    /*
         {
            "start": 0,
            "count": 10
         }
    */
    QMap<QString, QVariant> tmp;
    tmp.insert("start", start);
    tmp.insert("count", count);

    QJsonDocument doc = QJsonDocument::fromVariant(tmp);
    if(doc.isNull() || doc.isEmpty())
    {
        cout << "doc.isNull() || doc.isEmpty()";
        return 0;
    }

    return doc.toJson();
}

void sharelist::getFileJsonInfo(QByteArray data)
{
    /*
        {
            "user": "milo",
            "md5": "e8ea6031b779ac26c319ddf949ad9d8d",
            "create_time": "2020-06-21 21:35:25",
            "file_name": "test.mp4",
            "share_status": 0,
            "pv": 0,
            "url": "http://192.168.52.139:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
            "size": 27473666,
            "type": "mp4"
        }
            -- user	文件所属用户
            -- md5 文件md5
            -- create_time 文件创建时间
            -- file_name 文件名字
            -- shared_status 共享状态, 0为没有共享， 1为共享
            -- pv 文件下载量，默认值为0，下载一次加1
            -- url 文件url
            -- size 文件大小, 以字节为单位
            -- type 文件类型： png, zip, mp4……
    */
    // 将来源数据json转化为JsonDocument
    // 由QByteArray对象构造一个QJsonDocument对象，用于我们的读写操作
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(data, &error);
    if(error.error == QJsonParseError::NoError)
    {
        if(doc.isNull() || doc.isEmpty())
        {
            cout << "doc.isNull() || doc.isEmpty()";
            return;
        }

        if(doc.isObject())
        {
            QJsonObject obj = doc.object();
            QJsonArray array = obj.value("files").toArray();

            int size = array.size();
            cout << "size = " << size;

            for(int i = 0; i < size; ++i)
            {
                QJsonObject tmp = array[i].toObject();
                /*
                    文件信息
                    struct FileInfo
                    {
                        QString md5;            // 文件md5码
                        QString fileName;       // 文件名字
                        QString user;           // 用户
                        QString createTime;     // 上传时间
                        QString url;            // url
                        QString type;           // 文件类型
                        qint64 size;            // 文件大小
                        int shareStatus;        // 是否共享, 1共享， 0不共享
                        int pv;                 // 下载量
                        QListWidgetItem *item;  // list widget 的item
                    };

                    {
                        "user": "milo",
                        "md5": "e8ea6031b779ac26c319ddf949ad9d8d",
                        "create_time": "2020-06-21 21:35:25",
                        "file_name": "test.mp4",
                        "share_status": 0,
                        "pv": 0,
                        "url": "http://192.168.52.139:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
                        "size": 27473666,
                        "type": "mp4"
                    }
                */
                FileInfo* info = new FileInfo;
                info->user = tmp.value("user").toString();
                info->filename = tmp.value("file_name").toString();
                info->md5 = tmp.value("md5").toString();
                info->createTime = tmp.value("create_time").toString();
                info->url = tmp.value("url").toString();
                info->type = tmp.value("type").toString();
                info->size = tmp.value("size").toInt();
                info->pv = tmp.value("pv").toInt();
                info->shareStatus = tmp.value("share_status").toInt();
                QString type = info->type + ".png";
                info->icon = QIcon(m_cm.getFileType(type));
                info->item = new QListWidgetItem(info->icon, info->filename);
                m_shareFileList.append(info);
            }
        }
    }
    else
    {
        cout << "error = " << error.errorString();
    }
}

void sharelist::dealSelectdFile(QString cmd)
{
    QListWidgetItem* item = ui->listWidget->currentItem();
    if(item == nullptr)
    {
        return;
    }

    int num = m_shareFileList.size();
    for(int i = 0; i < num; ++i)
    {
        if(m_shareFileList.at(i)->item == item)
        {
            if(cmd == "property")
            {
                getFileProperty(m_shareFileList.at(i));
            }
            else if(cmd == "cancel")
            {
                cancelSharingFile(m_shareFileList.at(i));
            }
            else if(cmd == "save")
            {
                transferFile(m_shareFileList.at(i));
            }
        }
    }
}

void sharelist::getFileProperty(FileInfo *info)
{
    FilePropertyInfo dlg;
    dlg.setInfo(info);
    dlg.exec();
}

void sharelist::cancelSharingFile(FileInfo *info)
{
    if(info->shareStatus == 0)
    {
        QMessageBox::warning(this, "此文件没有分享", "此文件没有分享！！！");
        return;
    }

    /*
    {
        "user": "milo",
        "token": "xxxx",
        "md5": "xxx",
        "filename": "xxx"
    }
    */
    QNetworkRequest request;

    LoginInfoInstance* login = LoginInfoInstance::getInstance();
    QString url = QString("http://%1:%2/dealsharefile?cmd=cancel").arg(login->getIp()).arg(login->getPort());
    request.setUrl(QUrl(url));

    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    QByteArray data = setShareFileJson(login->getUser(), login->getToken(), info->md5, info->filename);
    QNetworkReply* reply = m_manager->post(request, data);
    if(reply == nullptr)
    {
        cout << "reply == nullptr";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        if(reply->error() != QNetworkReply::NoError)
        {
            cout << reply->errorString();
            reply->deleteLater();
            return;
        }

        QByteArray array = reply->readAll();

        reply->deleteLater();
        /*
            取消分享：
                成功：{"code":"018"}
                失败：{"code":"019"}
                不是本人：{"code":"110"}
        */
        QString code = m_cm.getCode(array);
        if("111" == code)
        {
            QMessageBox::warning(this, "账户异常", "请重新登陆！！！");
            emit loginAgainSignal(); //发送重新登陆信号

            return; //中断
        }
        else if("018" == code)
        {
            for(int i = 0; i < m_shareFileList.size(); ++i)
            {
                if(m_shareFileList.at(i) == info)
                {
                    QListWidgetItem* item = info->item;
                    ui->listWidget->removeItemWidget(item);
                    delete item;

                    m_shareFileList.removeAt(i);
                    delete info;
                    break;
                }
            }
            QMessageBox::information(this, "操作成功", "此文件已取消分享！");
        }
        else if("110" == code)
        {
            QMessageBox::warning(this, "操作失败", "该文件不属于该用户！！！");
        }
        else
        {
            QMessageBox::warning(this, "操作失败", "取消分享文件操作失败！！！");
        }
    });
}

void sharelist::transferFile(FileInfo *info)
{
    LoginInfoInstance* login = LoginInfoInstance::getInstance();
    if(login->getUser() == info->user)
    {
        QMessageBox::warning(this, "操作失败", "此文件本就属于该用户，无需转存！！！");
        return;
    }

    QNetworkRequest request;

    QString url = QString("http://%1:%2/dealsharefile?cmd=save").arg(login->getIp()).arg(login->getPort());
    request.setUrl(QUrl(url));

    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    /*
       {
           "user": "milo",
           "token": "xxx",
           "md5": "xxx",
           "filename": "xxx"
       }
   */

    QByteArray data = setShareFileJson(login->getUser(), login->getToken(), info->md5, info->filename);
    QNetworkReply* reply = m_manager->post(request, data);
    if(reply == nullptr)
    {
        cout << "reply == nullptr";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        if(reply->error() != QNetworkReply::NoError)
        {
            cout << reply->errorString();
            reply->deleteLater();
            return;
        }

        QByteArray array = reply->readAll();
        reply->deleteLater();

        /*
          转存文件：
              成功：{"code":"020"}
              文件已存在：{"code":"021"}
              失败：{"code":"022"}
       */
        QString code = m_cm.getCode(array);
        if("020" == code)
        {
            QMessageBox::information(this, "操作成功", "该文件已经保存到该用户列表中！！！");
        }
        else if("021" == m_cm.getCode(array))
        {
            QMessageBox::warning(this, "操作失败", "此文件已存在，无需转存！！！");
        }
        else if("022" == m_cm.getCode(array))
        {
            QMessageBox::warning(this, "操作失败", "文件转存失败！！！");
        }
    });
}

QByteArray sharelist::setShareFileJson(QString user, QString token, QString md5, QString filename)
{
    /*
    {
        "user": "milo",
        "token": "xxxx",
        "md5": "xxx",
        "filename": "xxx"
    }
    */

    QMap<QString, QVariant> tmp;
    tmp.insert("user", user);
    tmp.insert("token", token);
    tmp.insert("md5", md5);
    tmp.insert("filename", filename);

    QJsonDocument doc = QJsonDocument::fromVariant(tmp);
    if(doc.isEmpty() || doc.isNull())
    {
        cout << "doc.isNULL || doc.isEmpty";
        return 0;
    }

    return doc.toJson();
}

void sharelist::addDownloadFiles()
{
    QListWidgetItem* item = ui->listWidget->currentItem();
    if(item == nullptr)
    {
        cout << "item == nullptr";
        return;
    }

    emit gotoTransfer(TransferStatus::Download);

    DownloadTask* p = DownloadTask::getInstance();
    if(p == nullptr)
    {
        cout << "DownloadTask::getInstance() error";
        return;
    }

    for(int i = 0; i < m_shareFileList.size(); ++i)
    {
        if(m_shareFileList.at(i)->item == item)
        {
            QString filePathName = QFileDialog::getSaveFileName(this, "选择保存文件路径", m_shareFileList.at(i)->filename);
            if(filePathName.isEmpty())
            {
                cout << "filePathName.isEmpty()";
                return;
            }

            /*
               下载文件：
                    成功：{"code":"009"}
                    失败：{"code":"010"}

                追加任务到下载队列
                参数：info：下载文件信息， filePathName：文件保存路径
                成功：0
                失败：
                  -1: 下载的文件是否已经在下载队列中
                  -2: 打开文件失败
            */

            int res = p->appendDownloadList(m_shareFileList.at(i), filePathName, true);
            if(res == -1)
            {
                QMessageBox::warning(this, "任务已存在", "任务已经在下载队列中！！！");
            }
            else if(res == -2)
            {
                LoginInfoInstance* login = LoginInfoInstance::getInstance();
                m_cm.writeRecord(login->getUser(), m_shareFileList.at(i)->filename, "010");
            }
            break;
        }
    }
}

void sharelist::dealFilePv(QString md5, QString filename)
{
    QNetworkRequest request; // 请求对象

    // 获取登陆信息实例
    LoginInfoInstance *login = LoginInfoInstance::getInstance(); // 获取单例

    // 127.0.0.1:80/dealsharefile?cmd=pv
    QString url = QString("http:// %1:%2/dealsharefile?cmd=pv").arg(login->getIp()).arg(login->getPort());
    request.setUrl(QUrl( url )); // 设置url
    cout << "url = " << url;

    // qt默认的请求头
    // request.setRawHeader("Content-Type","text/html");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");

    /*
    {
        "user": "milo",
        "md5": "xxx",
        "filename": "xxx"
    }
    */
    QByteArray data = setShareFileJson(login->getUser(), login->getToken(), md5, filename);

    QNetworkReply* reply = m_manager->post(request, data);
    if(reply == nullptr)
    {
        cout << "reply == nullptr";
        return;
    }

    connect(reply, &QNetworkReply::finished, [=]()
    {
        if(reply->error() != QNetworkReply::NoError)
        {
            cout << reply->errorString();
            reply->deleteLater();
            return;
        }

        QByteArray array = reply->readAll();

        reply->deleteLater();

        /*
            下载文件pv字段处理
                成功：{"code":"016"}
                失败：{"code":"017"}
        */
        QString code = m_cm.getCode(array);
        if("016" == code)
        {
            for(int i = 0; i < m_shareFileList.size(); ++i)
            {
                FileInfo* info = m_shareFileList.at(i);
                if(info->md5 == md5 && info->filename == filename)
                {
                    int pv = info->pv;
                    info->pv = pv+1;
                    break;
                }
            }
        }
        else
        {
            cout << "下载文件pv字段处理失败";
        }
    });
}
